package com.iwhalecloud.bss.kite.cucc.order.accept.constructor.inst;

import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.KiteMapUtils;
import com.iwhalecloud.bss.kite.cucc.order.accept.constructor.IDataConstructor;
import com.iwhalecloud.bss.kite.cucc.order.util.AcceptUtils;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.IInst;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.inst.KiteInst;
import com.iwhalecloud.bss.kite.manager.inst.change.KiteRelChange;
import com.iwhalecloud.bss.kite.manager.inst.graph.impl.RelEdge;
import com.iwhalecloud.bss.kite.manager.util.ManagerUtils;
import com.iwhalecloud.bss.kite.manager.util.RelTypeUtils;
import com.iwhalecloud.bss.kite.order.client.dto.InstContainer;
import com.iwhalecloud.bss.kite.order.client.dto.OrderRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 关系构造器
 * @param <I>
 */
public abstract class RelConstructor<I extends IInst> implements IDataConstructor<RelEdge, I> {

    /**
     * 获取实例表名
     * @return
     */
    public abstract String getTableName();

    /**
     * new一个新增的实例(actionType=A)
     * @param orderRequest
     * @param relEdge
     * @param instRelId
     * @return
     */
    public abstract I newInst(OrderRequest orderRequest, RelEdge relEdge, String instRelId);

    /**
     * 从数据库查询关系实例
     * @param sourceInstId
     * @param targetInstId
     * @param relType
     * @param custId
     * @return
     */
    public abstract I getInstRel(String sourceInstId, String targetInstId, String relType, String custId);

    @Override
    public boolean contains(OrderRequest orderRequest, String aInstId, String zInstId, Map<String, Object> params) {
        if (!ObjectUtils.allNotNull(orderRequest, params) || StringUtils.isAnyBlank(aInstId, zInstId)) {
            return false;
        }

        String relType = KiteMapUtils.getString(params, KEY_REL_TYPE);
        if (StringUtils.isBlank(relType)) {
            return false;
        }

        return Objects
            .nonNull(InstContainer.ofRequest(orderRequest).getInstRel(getTableName(), aInstId, zInstId, relType));
    }

    @Override
    public I build(OrderRequest orderRequest, RelEdge relEdge, Map<String, Object> params) {
        if (!ObjectUtils.allNotNull(orderRequest, relEdge)) {
            return null;
        }

        String instRelId = KiteMapUtils.getString(params, KEY_INST_REL_ID);
        I inst = convert(orderRequest, relEdge, instRelId);
        InstContainer.ofRequest(orderRequest).addInst(inst);
        return inst;
    }

    /**
     * 把实例关系边转换成关系实例
     * @param orderRequest
     * @param relEdge
     * @param instRelId
     * @return
     */
    @SuppressWarnings("unchecked")
    public I convert(OrderRequest orderRequest, RelEdge relEdge, String instRelId) {
        if (!ObjectUtils.allNotNull(orderRequest, relEdge) || Objects.equals(ActionType.X, relEdge.getActionType())) {
            return null;
        }

        IInst inst = null;
        if (isAddByCurrent(orderRequest, relEdge)) {
            inst = newInst(orderRequest, relEdge, instRelId);
        }
        else {
            String relType = RelTypeUtils.getRelTypeCode(relEdge);
            inst = getInstRel(relEdge.getSourceInstId(), relEdge.getTargetInstId(), relType, orderRequest.getCustId());
            if (Objects.nonNull(inst)) {
                if (Objects.equals(ActionType.D, relEdge.getActionType())) {
                    dismantleInstRel(orderRequest, inst, relEdge);
                }
                else {
                    boolean change = setChangeAttrs(orderRequest, relEdge, inst);
                    if (Objects.equals(ActionType.A.name(), inst.getActionType())) {
                        // 新增未竣工的actionType可能是A，如果有变动信息，actionType改为M，否则改为K
                        String actionType = change ? ActionType.M.name() : ActionType.K.name();
                        AcceptUtils.setActionType(inst, actionType);
                    }
                    else if (!Objects.equals(ActionType.A, relEdge.getActionType())) {
                        AcceptUtils.setActionType(inst, ManagerUtils.getEnumName(relEdge.getActionType()));
                    }
                }
            }
            else {
                inst = newInst(orderRequest, relEdge, instRelId);
            }
        }

        return (I) inst;
    }

    /**
     * 根据变动信息修改关系实例的属性值
     * @param orderRequest
     * @param relEdge
     * @param inst
     * @return
     */
    public boolean setChangeAttrs(OrderRequest orderRequest, RelEdge relEdge, IInst inst) {
        boolean change = false;
        if (!ObjectUtils.allNotNull(orderRequest, relEdge, inst)) {
            return change;
        }

        String key = ManagerUtils.join(relEdge.getSourceInstType(), relEdge.getSourceInstId());
        List<KiteRelChange> relChanges = orderRequest.getRelChangeMap().getOrDefault(key, new ArrayList<>());
        relChanges = relChanges.stream().filter(relChange -> {
            return Objects.equals(relEdge.getSourceInstId(), relChange.getSourceInstId())
                && Objects.equals(relEdge.getSourceInstType(), relChange.getSourceInstType())
                && Objects.equals(relEdge.getTargetInstId(), relChange.getTargetInstId())
                && Objects.equals(relEdge.getTargetInstType(), relChange.getTargetInstType())
                && Objects.equals(relEdge.getRelType(), relChange.getRelType());
        }).collect(Collectors.toList());
        for (KiteRelChange relChange : relChanges) {
            String fieldName = relChange.getFieldName();
            if (Objects.equals(KiteInst.ACTION_TYPE, fieldName)) {
                continue;
            }

            String newValue = relChange.getNewValue();
            // 空字符串转换成null，防止把空字符串set到number类型的字段入库时报错
            newValue = StringUtils.isNotBlank(newValue) ? newValue : null;
            KiteBeanUtils.setValueByName(inst, fieldName, newValue);
            change = true;
        }

        return change;
    }

    /**
     * 判断实例是否本次新增的，即使actionType=A也有可能不是本次新增的(新增未竣工actionType也是A)
     * @param orderRequest
     * @param relEdge
     * @return
     */
    public boolean isAddByCurrent(OrderRequest orderRequest, RelEdge relEdge) {
        if (!ObjectUtils.allNotNull(orderRequest, relEdge)) {
            return false;
        }

        String key = ManagerUtils.join(relEdge.getSourceInstType(), relEdge.getSourceInstId());
        List<KiteRelChange> relChanges = orderRequest.getRelChangeMap().getOrDefault(key, new ArrayList<>());
        for (KiteRelChange relChange : relChanges) {
            if (Objects.equals(relEdge.getSourceInstId(), relChange.getSourceInstId())
                && Objects.equals(relEdge.getSourceInstType(), relChange.getSourceInstType())
                && Objects.equals(relEdge.getTargetInstId(), relChange.getTargetInstId())
                && Objects.equals(relEdge.getTargetInstType(), relChange.getTargetInstType())
                && Objects.equals(relEdge.getRelType(), relChange.getRelType())
                && Objects.equals(KiteInst.ACTION_TYPE, relChange.getFieldName())
                && Objects.equals(ActionType.A.name(), relChange.getNewValue())) {
                return true;
            }
        }

        return false;
    }

    /**
     * 关系实例删除处理<br>
     * <li>删除非actionType属性的变动信息
     * <li>如果actionType变动信息的newValue不是D，则改成D，如果oldValue是D，则改成K
     * <li>如果没有变动信息，则补充一条actionType=D的变动信息
     * @param orderRequest
     * @param inst
     * @param relEdge
     */
    public static void dismantleInstRel(OrderRequest orderRequest, IInst inst, RelEdge relEdge) {
        if (!ObjectUtils.allNotNull(orderRequest, inst, relEdge)) {
            return;
        }

        String key = ManagerUtils.join(relEdge.getSourceInstType(), relEdge.getSourceInstId());
        List<KiteRelChange> relChanges = orderRequest.getRelChangeMap().get(key);
        if (Objects.isNull(relChanges)) {
            relChanges = new ArrayList<>();
            orderRequest.getRelChangeMap().put(key, relChanges);
        }
        // 删除非actionType属性的变动信息
        relChanges.removeIf(relChange -> {
            return Objects.equals(relEdge.getSourceInstId(), relChange.getSourceInstId())
                && Objects.equals(relEdge.getSourceInstType(), relChange.getSourceInstType())
                && Objects.equals(relEdge.getTargetInstId(), relChange.getTargetInstId())
                && Objects.equals(relEdge.getTargetInstType(), relChange.getTargetInstType())
                && Objects.equals(relEdge.getRelType(), relChange.getRelType())
                && !Objects.equals(KiteInst.ACTION_TYPE, relChange.getFieldName());
        });

        KiteRelChange relChange = new KiteRelChange();
        relChange.setSourceInstId(relEdge.getSourceInstId());
        relChange.setSourceInstType(relEdge.getSourceInstType());
        relChange.setTargetInstId(relEdge.getTargetInstId());
        relChange.setTargetInstType(relEdge.getTargetInstType());
        relChange.setRelType(relEdge.getRelType());
        relChange.setFieldName(KiteInst.ACTION_TYPE);
        relChange.setOldValue(ActionType.K.name());
        relChange.setNewValue(ActionType.D.name());

        KiteRelChange change = getRelChange(relChanges, relChange);
        if (Objects.nonNull(change)) {
            if (!Objects.equals(ActionType.D.name(), change.getNewValue())) {
                change.setNewValue(ActionType.D.name());
            }
            if (Objects.equals(ActionType.D.name(), change.getOldValue())) {
                change.setOldValue(ActionType.K.name());
            }
        }
        else {
            // 如果没有变动信息，则补充一条actionType=D的变动信息
            relChanges.add(relChange);
        }

        AcceptUtils.setActionType(inst, ActionType.D.name());
    }

    /**
     * 获取关系变动信息
     * @param relChanges
     * @param relChange
     * @return
     */
    public static KiteRelChange getRelChange(List<KiteRelChange> relChanges, KiteRelChange relChange) {
        if (CollectionUtils.isEmpty(relChanges) || Objects.isNull(relChange)) {
            return null;
        }

        for (KiteRelChange change : relChanges) {
            if (Objects.equals(relChange.getSourceInstId(), change.getSourceInstId())
                && Objects.equals(relChange.getSourceInstType(), change.getSourceInstType())
                && Objects.equals(relChange.getTargetInstId(), change.getTargetInstId())
                && Objects.equals(relChange.getTargetInstType(), change.getTargetInstType())
                && Objects.equals(relChange.getRelType(), change.getRelType())
                && Objects.equals(relChange.getFieldName(), change.getFieldName())) {
                return change;
            }
        }

        return null;
    }
}
